#include "HY1C_out.h"
/* ========================================================================
 *  Procedures create, read, and write HDF msvalidation pixel data
 *
 * int msval_append(char *valfile, msvalstr valstr) - creates HDF, if
 *			it does not exist already, and appends data
 * int msval_read(char *valfile, int32_t subsmpl, msvalstr *valstr) - 
 *			reads subsampled pixel validation data and
 * 			allocates memory and data to the valstr structure
 * int msval_add(char *valfile, int32_t subsmpl, msvalstr *valstr, int32_t *npixs, int32_t *ngranuls) 
 *                      reads validation data from an hdf file,
 *          		subsamples if needed, and adds pixel and granule
 *          		data to an already existing valstr structure
 *
 *     Programmer     Organization      Date       Description of change
 *   --------------   ------------    --------     ---------------------
 *   Ewa Kwiatkowska   SAIC       13 January 2004    Original development
 *   Ewa Kwiatkowska   SAIC       20 October 2004    Introduced user defined list
 *						     of L2 and L3 products
 *						     All L2 and L3 products are float32
 *						     except for L2 l2_flags, mside, detnum, pixnum
 *   Ewa Kwiatkowska   SAIC       7 November 2007    Added nscenes, nobs product
 *   Joel Gales        Futurtech  3 November 2012    Add ds_id.fftype
 *
 * ======================================================================== */


#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <libgen.h>
#include <math.h>

#include "l12_proto.h"
#include "passthebuck.h"
#include "l2prod_struc.h"
#include "filehandle.h"
#include "hdf_utils.h"
#include "mfhdf.h"
#include "msl2val_struc.h"


int rdstrideSDS(int32 fileID, char *sdsname, int32 stride[2], VOIDP array_data);
int read_glbl_attr(int32 sd_id, char *name, VOIDP ptr);
int msval_read(char *valfile, int32_t subsmpl, msvalstr *valstr);
int msval_npixs(char *valfile, int32_t subsmpl, int32_t *sensorID, int32_t *npixs, int32_t *ngranuls);
int msval_create(char *valfile, int32 *sd_id, msvalstr valstr, int32_t npixs);
int msval_readblocks(char *valfile, int32 *sd_id, int32_t *spix, int32_t *totalpixs, msvalstr *valstr);
int msval_writeblocks(char *valfile, int32 sd_id, int32_t *spix, msvalstr valstr, int32_t nfiles);




int msval_create(char *valfile, int32 *sd_id, msvalstr valstr, int32_t npixs)
{

    char title[255], *ch;
    l2prodstr p, *ptr;
    int i;
    
    

    sprintf(title, "%s Level-2 validation pixels", sensorName[valstr.l2sensorID]);

    
    *sd_id = SDstart(valfile, DFACC_CREATE);
    if (*sd_id == FAIL) {
       HY1C_out("-E- %s line %d: Could not create HDF file, %s .\n",__FILE__,__LINE__,valfile);
       return(HDF_FUNCTION_ERROR);
    }   
    
    /*                                                                  */
    /* Create the pixel SDSes                                           */
    /* ---------------------------------------------------------------- */
    /*                                                                  */
    idDS ds_id;
    ds_id.fid = *sd_id;
    ds_id.fftype = FMT_L2HDF;

    PTB( SetChrGA(ds_id, "Title", title) );
    PTB( SetI32GA(ds_id, "sensorID\0",(int32)valstr.l2sensorID) );
    PTB( SetI32GA(ds_id, "L3 validation sensorID", valstr.l3sensorID) );
    PTB( SetChrGA(ds_id, "Input Parameters", valstr.input_parms));
    
    PTB( CreateSDS(
    *sd_id,                                          /* file id         */
    "fileID",                                        /* short name      */
    "ID of the File",                                /* long name       */
    NULL,                                            /* standard name   */
    "dimensionless",                                 /* units           */
    0, 0,                                            /* valid range     */
    0,0,                                             /* slope, offset   */
    DFNT_INT16,                                      /* HDF number type */
    1,                                               /* rank            */
    npixs, 1, 1,                                     /* dimension sizes */
    "Number of Pixels", NULL, NULL                   /* dimension names */
    ) );

    PTB( CreateSDS(
    *sd_id,                                          /* file id         */
    "year",                                          /* short name      */
    "Pixel year",                                    /* long name       */
    NULL,                                            /* standard name   */
    "years",                                         /* units           */
    1996, 2038,                                      /* valid range     */
    0,0,                                             /* slope, offset   */
    DFNT_INT16,                                      /* HDF number type */
    1,                                               /* rank            */
    npixs, 1, 1,                                     /* dimension sizes */
    "Number of Pixels", NULL, NULL                   /* dimension names */
    ) );

    PTB( CreateSDS(
    *sd_id,                                          /* file id         */
    "day",                                           /* short name      */
    "Pixel day of year",                             /* long name       */
    NULL,                                            /* standard name   */
    "days",                                          /* units           */
    0,366,                                           /* valid range     */
    0,0,                                             /* slope, offset   */
    DFNT_INT16,                                      /* HDF number type */
    1,                                               /* rank            */
    npixs, 1, 1,                                     /* dimension sizes */
    "Number of Pixels", NULL, NULL                   /* dimension names */
    ) );

    PTB( CreateSDS(
    *sd_id,                                          /* file id         */
    "msec",                                          /* short name      */
    "Pixel time, milliseconds of day",               /* long name       */
    NULL,                                            /* standard name   */
    "milliseconds",                                  /* units           */
    0,0,                                             /* valid range     */
    0,0,                                             /* slope, offset   */
    DFNT_INT32,                                      /* HDF number type */
    1,                                               /* rank            */
    npixs, 1, 1,                                     /* dimension sizes */
    "Number of Pixels", NULL, NULL                   /* dimension names */
    ) );

    PTB( CreateSDS(
    *sd_id,                                          /* file id         */
    "iscan",                                         /* short name      */
    "Scan-line number for the pixel",                /* long name       */
    NULL,                                            /* standard name   */
    "dimensionless",                                 /* units           */
    0,0,                                             /* valid range     */
    0,0,                                             /* slope, offset   */
    DFNT_INT16,                                      /* HDF number type */
    1,                                               /* rank            */
    npixs, 1, 1,                                     /* dimension sizes */
    "Number of Pixels", NULL, NULL                   /* dimension names */
    ) );

    PTB( CreateSDS(
    *sd_id,                                          /* file id         */
    "nscenes",                                       /* short name      */
    "Number of scenes in L3 matching bin",           /* long name       */
    NULL,                                            /* standard name   */
    "dimensionless",                                 /* units           */
    0,0,                                             /* valid range     */
    0,0,                                             /* slope, offset   */
    DFNT_INT16,                                      /* HDF number type */
    1,                                               /* rank            */
    npixs, 1, 1,                                     /* dimension sizes */
    "Number of Pixels", NULL, NULL                   /* dimension names */
    ) );

    PTB( CreateSDS(
    *sd_id,                                          /* file id         */
    "nobs",                                          /* short name      */
    "Number of observations in L3 matching bin",     /* long name       */
    NULL,                                            /* standard name   */
    "dimensionless",                                 /* units           */
    0,0,                                             /* valid range     */
    0,0,                                             /* slope, offset   */
    DFNT_INT16,                                      /* HDF number type */
    1,                                               /* rank            */
    npixs, 1, 1,                                     /* dimension sizes */
    "Number of Pixels", NULL, NULL                   /* dimension names */
    ) );

    PTB( CreateSDS(
    *sd_id,                                          /* file id         */
    "lon",                                           /* short name      */
    "Pixel longitude",                               /* long name       */
    NULL,                                            /* standard name   */
    "degrees",                                       /* units           */
    -180.0, 180.0,                                   /* valid range     */
    0,0,                                             /* slope, offset   */
    DFNT_FLOAT32,                                    /* HDF number type */
    1,                                               /* rank            */
    npixs, 1, 1,                                     /* dimension sizes */
    "Number of Pixels", NULL, NULL                   /* dimension names */
    ) );

    PTB( CreateSDS(
    *sd_id,                                          /* file id         */
    "lat",                                           /* short name      */
    "Pixel latitude",                                /* long name       */
    NULL,                                            /* standard name   */
    "degrees",                                       /* units           */
    -90.0, 90.0,                                     /* valid range     */
    0,0,                                             /* slope, offset   */
    DFNT_FLOAT32,                                    /* HDF number type */
    1,                                               /* rank            */
    npixs, 1, 1,                                     /* dimension sizes */
    "Number of Pixels", NULL, NULL                   /* dimension names */
    ) );
    
    
    /*                                                                  */
    /* Create the geophysical SDSes for the L3 vicarious products       */
    /* ---------------------------------------------------------------- */
    /*                                                                  */
    ptr = &p;
    for (i=0; i<valstr.nl3prods; i++) {

        if ((ch = strstr(valstr.l3prods[i], "_vic")) != NULL) {
	    ch[0] = '\x0';
	}
	
        if ((ptr = get_l2prod_index(valstr.l3prods[i],valstr.l3sensorID,
               valstr.nl3bands,0,1,valstr.l3Lambda)) == NULL) {
            fHY1C_out(stderr,
            "-E- %s line %d: product index failure.\n",
            __FILE__,__LINE__);
            return(FATAL_ERROR);
        };
	strcat(valstr.l3prods[i], "_vic\x0");

        PTB( CreateSDS(
        *sd_id,                                      /* file id         */
        valstr.l3prods[i],                           /* short name      */
        ptr->title,                                  /* long name       */
        ptr->standard_name,                          /* standard name   */
        ptr->units,                                  /* units           */
        ptr->min, ptr->max,                          /* valid range     */
        0.0, 0.0,                                    /* slope, offset   */
        DFNT_FLOAT32,                                /* HDF number type */
        1,                                           /* number of dims  */
        npixs, 1, 1,                                 /* dimension sizes */
        "Number of Pixels", NULL, NULL               /* dimension names */
        ) );
	
    }
    
    
    /*                                                                  */
    /* Create the geophysical SDSes for the L2 validation products      */
    /* ---------------------------------------------------------------- */
    /*                                                                  */
    for (i=0; i<valstr.nl2prods; i++) {

        if ((ptr = get_l2prod_index(valstr.l2prods[i],valstr.l2sensorID,
               valstr.nl2bands,0,1,valstr.l2Lambda)) == NULL) {
            fHY1C_out(stderr,
            "-E- %s line %d: product index failure.\n",
            __FILE__,__LINE__);
            return(FATAL_ERROR);
        };
	
	if (strcmp(valstr.l2prods[i], "l2_flags") == 0) {
	
    	    PTB( CreateSDS(
    	    *sd_id,                                      /* file id         */
            valstr.l2prods[i],                           /* short name      */
            ptr->title,                                  /* long name       */
            ptr->standard_name,                          /* standard name   */
            ptr->units,                                  /* units           */
            ptr->min, ptr->max,                          /* valid range     */
            0.0, 0.0,                                    /* slope, offset   */
            DFNT_INT32,                                  /* HDF number type */
            1,                                           /* number of dims  */
            npixs, 1, 1,                                 /* dimension sizes */
            "Number of Pixels", NULL, NULL               /* dimension names */
            ) );
	    
	} else
    	if ((strcmp(valstr.l2prods[i], "mside") == 0) || (strcmp(valstr.l2prods[i], "detnum") == 0)) {
	
    	    PTB( CreateSDS(
    	    *sd_id,                                      /* file id         */
            valstr.l2prods[i],                           /* short name      */
            ptr->title,                                  /* long name       */
            ptr->standard_name,                          /* standard name   */
            ptr->units,                                  /* units           */
            ptr->min, ptr->max,                          /* valid range     */
            0.0, 0.0,                                    /* slope, offset   */
            DFNT_UINT8,                                  /* HDF number type */
            1,                                           /* number of dims  */
            npixs, 1, 1,                                 /* dimension sizes */
            "Number of Pixels", NULL, NULL               /* dimension names */
            ) );
	    
	} else
    	if (strcmp(valstr.l2prods[i], "pixnum") == 0) {
	
    	    PTB( CreateSDS(
    	    *sd_id,                                      /* file id         */
            valstr.l2prods[i],                           /* short name      */
            ptr->title,                                  /* long name       */
            ptr->standard_name,                          /* standard name   */
            ptr->units,                                  /* units           */
            ptr->min, ptr->max,                          /* valid range     */
            0.0, 0.0,                                    /* slope, offset   */
            DFNT_INT16,                                  /* HDF number type */
            1,                                           /* number of dims  */
            npixs, 1, 1,                                 /* dimension sizes */
            "Number of Pixels", NULL, NULL               /* dimension names */
            ) );

	} else {

            PTB( CreateSDS(
            *sd_id,                                      /* file id         */
            valstr.l2prods[i],                           /* short name      */
            ptr->title,                                  /* long name       */
            ptr->standard_name,                          /* standard name   */
            ptr->units,                                  /* units           */
            ptr->min, ptr->max,                          /* valid range     */
            0.0, 0.0,                                    /* slope, offset   */
            DFNT_FLOAT32,                                /* HDF number type */
            1,                                           /* number of dims  */
            npixs, 1, 1,                                 /* dimension sizes */
            "Number of Pixels", NULL, NULL               /* dimension names */
            ) );
	}

    }

    
    return(LIFE_IS_GOOD);
    
}





int msval_append(char *valfile, msvalstr valstr)
{

    int32 sd_id_old, sd_id;
    char  command[2*FILENAME_MAX], name[FILENAME_MAX], name1[FILENAME_MAX], *tempname;
    int   status, exists;
    int32_t  spix_old, spix, total_old, i;
    msvalstr valstr_old;
    

    spix_old = -1;
    total_old = 0;
    valstr_old.data = NULL;
    if (msval_readblocks(valfile, &sd_id_old, &spix_old, &total_old, &valstr_old) != LIFE_IS_GOOD) {
    	HY1C_out("-E- %s line %d: Cannot read already existing SDS data %s\n",__FILE__,__LINE__,valfile);
    	return(HDF_FUNCTION_ERROR);
    }

    if (valstr_old.npixs == 0L) exists = 0; else {
    	exists = 1;
    	if (valstr_old.l2sensorID != valstr.l2sensorID) {
    	    HY1C_out("-E- %s line %d: Attempt to write into a file whose data come from a different sensor %s\n",__FILE__,__LINE__,sensorName[valstr_old.l2sensorID]);
	    free_valstr(valstr_old, 1);
	    status = SDend(sd_id_old);
            return(HDF_FUNCTION_ERROR);
    	}
    	if (valstr_old.l3sensorID != valstr.l3sensorID) {
    	    HY1C_out("-E- %s line %d: Attempt to write into a file whose data come from different validations sensors %s\n",__FILE__,__LINE__,sensorName[valstr_old.l3sensorID]);
	    free_valstr(valstr_old, 1);
	    status = SDend(sd_id_old);
            return(HDF_FUNCTION_ERROR);
    	}
    }
    	    
    
    if (exists) { 
   
	strcpy(name1, valfile);
	tempname = dirname(name1);
	strcpy(name, tempname);
	strcat(name, "/temp.hdf");
	
	if (msval_create(name, &sd_id, valstr, total_old+valstr.npixs) != LIFE_IS_GOOD) {
    	    HY1C_out("-E- %s line %d: Cannot read already existing SDS data %s\n",__FILE__,__LINE__,name);
	    free_valstr(valstr_old, 1);
	    status = SDend(sd_id);
	    status = SDend(sd_id_old);
            return(HDF_FUNCTION_ERROR);
    	}
	
	spix = 0L;
		
	do {
	    
	    if (msval_writeblocks(name, sd_id, &spix, valstr_old, 0L) != LIFE_IS_GOOD) {
    	    	HY1C_out("-E- %s line %d: Cannot write existing SDS data into the temp file %s\n",__FILE__,__LINE__,name);
	    	free_valstr(valstr_old, 1);
	    	status = SDend(sd_id);
	        status = SDend(sd_id_old);
    	    	return(HDF_FUNCTION_ERROR);
	    }
	    
	    if (msval_readblocks(valfile, &sd_id_old, &spix_old, &total_old, &valstr_old) != LIFE_IS_GOOD) {
    	    	HY1C_out("-E- %s line %d: Cannot read already existing SDS data %s\n",__FILE__,__LINE__,valfile);
	    	free_valstr(valstr_old, 1);
	    	status = SDend(sd_id);
    	    	return(HDF_FUNCTION_ERROR);
	    }

    	} while (valstr_old.npixs > 0L);


	for (i=0; i<valstr.npixs; i++) valstr.fileID[i] += (int16)valstr_old.nfiles;
	
	if (msval_writeblocks(name, sd_id, &spix, valstr, valstr_old.nfiles) != LIFE_IS_GOOD) {
    	    HY1C_out("-E- %s line %d: Cannot write new SDS data into the temp file %s\n",__FILE__,__LINE__,name);
	    status = SDend(sd_id);
    	    return(HDF_FUNCTION_ERROR);
	}
	    
    	if (SDend(sd_id) == FAIL) {
            HY1C_out("-E- %s line %d: Could not close HDF file, %s.\n",__FILE__,__LINE__,name);
            return(HDF_FUNCTION_ERROR);
    	}
	
	sprintf(command, "mv %s %s", name, valfile);
	system(command);

    } else {
    
    	if (msval_create(valfile, &sd_id, valstr, valstr.npixs) != LIFE_IS_GOOD) {
     	    HY1C_out("-E- %s line %d: Could not open HDF file, %s .\n",__FILE__,__LINE__,valfile);
	    status = SDend(sd_id);
            return(HDF_FUNCTION_ERROR);
    	}
	
	spix = 0L;
	
	if (msval_writeblocks(valfile, sd_id, &spix, valstr, 0L) != LIFE_IS_GOOD) {
    	    HY1C_out("-E- %s line %d: Cannot write new SDS data into the file %s\n",__FILE__,__LINE__,valfile);
	    status = SDend(sd_id);
    	    return(HDF_FUNCTION_ERROR);
	}
	    
    	if (SDend(sd_id) == FAIL) {
            HY1C_out("-E- %s line %d: Could not close HDF file, %s.\n",__FILE__,__LINE__,valfile);
            return(HDF_FUNCTION_ERROR);
    	}
    }
    
    
    return(LIFE_IS_GOOD);
    
}    



/* ------------------------------------------------------         */
/* msval_read() - reads validation data and 	          */
/*          subsamples if needed       			          */
/*          calptr comprises the actual data for npixs pixels     */
/*          memory is allocated depending on the npixs in the file*/
/* ------------------------------------------------------         */

int msval_read(char *valfile, int32_t subsmpl, msvalstr *valstr)
{

    int32 sd_id, sds_id;
    int32 dim_sizes[H4_MAX_VAR_DIMS];
    int32 stride[2], n_datasets, n_file_attr, rank, num_type, attributes;
    intn  status;
    char  name[H4_MAX_NC_NAME];
    int32_t  nfiles=0, totalpix=0, i, l;
    char  input_parms[16384], *ch;
    
    
    if (subsmpl <= 1) subsmpl = 1;
    
    sd_id = SDstart(valfile, DFACC_RDONLY);
    if (sd_id == FAIL) {
       	HY1C_out("-E- %s line %d: Could not open HDF file, %s .\n",__FILE__,__LINE__,valfile);
       	return(HDF_FUNCTION_ERROR);
    }
    
    strcpy(name, "sensorID\0");
    read_glbl_attr(sd_id, name, (VOIDP) &(valstr->l2sensorID));
    strcpy(name, "L3 validation sensorID\0");
    read_glbl_attr(sd_id, name, (VOIDP) &(valstr->l3sensorID));
    strcpy(name, "Input Parameters\0");
    read_glbl_attr(sd_id, name, (VOIDP) input_parms);
    l = strlen(input_parms);
    if ((valstr->input_parms = (char *)malloc((l+1)*sizeof(char))) == NULL) {
        HY1C_out("-E- %s line %d: Error allocating memory to MSl2validate input parameter text.\n",__FILE__,__LINE__);
    	return(HDF_FUNCTION_ERROR);
    }
    strncpy(valstr->input_parms, input_parms, l);
    valstr->input_parms[l] = '\x0';
    

    valstr->nl2prods = 1000;
    if ((valstr->l2prods = (prname *)malloc(valstr->nl2prods*sizeof(prname))) == NULL) {
        HY1C_out("-E- %s line %d: Error allocating memory to l2 product names.\n",__FILE__,__LINE__);
    	return(HDF_FUNCTION_ERROR);
    }
    valstr->nl2prods = 0;
    valstr->nl3prods = 1000;
    if ((valstr->l3prods = (prname *)malloc(valstr->nl3prods*sizeof(prname))) == NULL) {
        HY1C_out("-E- %s line %d: Error allocating memory to L3 product names.\n",__FILE__,__LINE__);
    	return(HDF_FUNCTION_ERROR);
    }
    valstr->nl3prods = 0;
   
    
    nfiles = 0L;
    do {
        sprintf(name, "filename%d", nfiles);
	    
  	if (SDfindattr(sd_id,name) == FAIL) break; else ++nfiles;
	
    } while (1);

    
    if (nfiles == 0L) {
       	HY1C_out("-E- %s line %d: Could not find filename attributes, %s .\n",__FILE__,__LINE__,name);
       	return(HDF_FUNCTION_ERROR);
    }
    
    
    SDfileinfo(sd_id, &n_datasets, &n_file_attr);
    
    
    for (i=0; i<n_datasets; i++) {
    
    	sds_id = SDselect(sd_id, i);
	status = SDgetinfo(sds_id, name, &rank, dim_sizes, &num_type, &attributes);
	
	if (strcmp(name, "fileID") == 0) {
    	    if (getDims(sd_id, name, dim_sizes) != 0) {
       		HY1C_out("-E- %s line %d: Could not read HDF file dimensions, %s .\n",__FILE__,__LINE__,valfile);
        	status = SDend(sd_id);
       		return(HDF_FUNCTION_ERROR);
    	    }
    	    if (dim_sizes[0] < 0) {
    		HY1C_out("-E- %s line %d: The rank of the requested parameter (%s) is incorrect\n",__FILE__,__LINE__,name);
        	status = SDend(sd_id);
    		return(HDF_FUNCTION_ERROR);
    	    }
    	    if (dim_sizes[0] == SD_UNLIMITED) HY1C_out("  Dimension SD_UNLIMITED"); else totalpix = (int32_t)dim_sizes[0];
	}
	else 
	if (strcmp(name, "year") == 0) ;
	else 
	if (strcmp(name, "day") == 0) ;
	else 
	if (strcmp(name, "msec") == 0) ;
	else 
	if (strcmp(name, "iscan") == 0) ;
	else 
	if (strcmp(name, "nscenes") == 0) ;
	else 
	if (strcmp(name, "nobs") == 0) ;
	else 
	if (strcmp(name, "lon") == 0) ;
	else 
	if (strcmp(name, "lat") == 0) ;
	else 
        if ((ch = strstr(name, "_vic")) != NULL) {
	    
	    strcpy(valstr->l3prods[valstr->nl3prods], name);
	    valstr->nl3prods++;
	}
	else {
	    
	    strcpy(valstr->l2prods[valstr->nl2prods], name);
	    valstr->nl2prods++;
    	} 
    }
    
    if ((valstr->l2prods = (prname *)realloc((void *)valstr->l2prods, valstr->nl2prods*sizeof(prname))) == NULL) {
        HY1C_out("-E- %s line %d: Error reallocating memory to l2 product names.\n",__FILE__,__LINE__);
    	return(HDF_FUNCTION_ERROR);
    }
    if ((valstr->l3prods = (prname *)realloc((void *)valstr->l3prods, valstr->nl3prods*sizeof(prname))) == NULL) {
        HY1C_out("-E- %s line %d: Error reallocating memory to L3 product names.\n",__FILE__,__LINE__);
    	return(HDF_FUNCTION_ERROR);
    }
    valstr->l2Lambda = NULL;
    valstr->l3Lambda = NULL;
    
    
    
    totalpix = (totalpix+subsmpl-1)/subsmpl;
    
    l = alloc_valstr(nfiles, totalpix, valstr);
        

    for (i=0; i<nfiles; i++) {
	sprintf(name, "filename%d", i);
	    
	if (read_glbl_attr(sd_id, name, (VOIDP) valstr->filenames[i]) != SUCCESS) {
	    HY1C_out("-E- %s line %d: Error reading filename attributes (%s)\n",__FILE__,__LINE__,name);
            free_valstr(*valstr, 1);
	    status = SDend(sd_id);
    	    return(HDF_FUNCTION_ERROR);
	}
    
    }
	        
	    
    if (subsmpl <= 1) {
    	PTB( rdSDS(sd_id,"fileID\0",0,0,0,0,(VOIDP)valstr->fileID) );
    	PTB( rdSDS(sd_id,"year\0",0,0,0,0,(VOIDP)valstr->year) );
    	PTB( rdSDS(sd_id,"day\0",0,0,0,0,(VOIDP)valstr->day) );
    	PTB( rdSDS(sd_id,"msec\0",0,0,0,0,(VOIDP)valstr->msec) );
    	PTB( rdSDS(sd_id,"lon\0",0,0,0,0,(VOIDP)valstr->lon) );
    	PTB( rdSDS(sd_id,"lat\0",0,0,0,0,(VOIDP)valstr->lat) );
    	PTB( rdSDS(sd_id,"iscan\0",0,0,0,0,(VOIDP)valstr->iscan) );
    	PTB( rdSDS(sd_id,"nscenes\0",0,0,0,0,(VOIDP)valstr->nscenes) );
    	PTB( rdSDS(sd_id,"nobs\0",0,0,0,0,(VOIDP)valstr->nobs) );
	for (i=0; i<valstr->nl3prods; i++)
	   PTB( rdSDS(sd_id,valstr->l3prods[i],0,0,0,0,(VOIDP)&(valstr->data_vic[i*totalpix])) );
	   
	l = 0;
	for (i=0; i<valstr->nl2prods; i++) {
    	    if (strcmp(valstr->l2prods[i], "l2_flags") == 0) {
	   	PTB( rdSDS(sd_id,valstr->l2prods[i],0,0,0,0,(VOIDP)valstr->l2_flags) );
    	    } else
    	    if (strcmp(valstr->l2prods[i], "mside") == 0) {
	   	PTB( rdSDS(sd_id,valstr->l2prods[i],0,0,0,0,(VOIDP)valstr->mside) );
    	    } else
    	    if (strcmp(valstr->l2prods[i], "detnum") == 0) {
	   	PTB( rdSDS(sd_id,valstr->l2prods[i],0,0,0,0,(VOIDP)valstr->detnum) );
    	    } else
    	    if (strcmp(valstr->l2prods[i], "pixnum") == 0) {
	   	PTB( rdSDS(sd_id,valstr->l2prods[i],0,0,0,0,(VOIDP)valstr->pixnum) );
    	    } else {
	        PTB( rdSDS(sd_id,valstr->l2prods[i],0,0,0,0,(VOIDP)&(valstr->data_val[l*totalpix])) );
		++l;
	    }
	}
	
    } else {
    
	stride[0] = subsmpl;
	stride[1] = 1;
	PTB( rdstrideSDS(sd_id,"fileID\0",stride,(VOIDP)valstr->fileID) );
	PTB( rdstrideSDS(sd_id,"year\0",stride,(VOIDP)valstr->year) );
    	PTB( rdstrideSDS(sd_id,"day\0",stride,(VOIDP)valstr->day) );
    	PTB( rdstrideSDS(sd_id,"msec\0",stride,(VOIDP)valstr->msec) );
    	PTB( rdstrideSDS(sd_id,"lon\0",stride,(VOIDP)valstr->lon) );
    	PTB( rdstrideSDS(sd_id,"lat\0",stride,(VOIDP)valstr->lat) );
    	PTB( rdstrideSDS(sd_id,"iscan\0",stride,(VOIDP)valstr->iscan) );
    	PTB( rdstrideSDS(sd_id,"nscenes\0",stride,(VOIDP)valstr->nscenes) );
    	PTB( rdstrideSDS(sd_id,"nobs\0",stride,(VOIDP)valstr->nobs) );
	for (i=0; i<valstr->nl3prods; i++)
	   PTB( rdstrideSDS(sd_id,valstr->l3prods[i],stride,(VOIDP)(valstr->data_vic+i*totalpix)) );
	   
	l = 0;
	for (i=0; i<valstr->nl2prods; i++) {
    	    if (strcmp(valstr->l2prods[i], "l2_flags\0") == 0) {
	   	PTB( rdstrideSDS(sd_id,valstr->l2prods[i],stride,(VOIDP)valstr->l2_flags) );
    	    } else
    	    if (strcmp(valstr->l2prods[i], "mside\0") == 0) {
	   	PTB( rdstrideSDS(sd_id,valstr->l2prods[i],stride,(VOIDP)valstr->mside) );
    	    } else
    	    if (strcmp(valstr->l2prods[i], "detnum\0") == 0) {
	   	PTB( rdstrideSDS(sd_id,valstr->l2prods[i],stride,(VOIDP)valstr->detnum) );
    	    } else
    	    if (strcmp(valstr->l2prods[i], "pixnum\0") == 0) {
	   	PTB( rdstrideSDS(sd_id,valstr->l2prods[i],stride,(VOIDP)valstr->pixnum) );
    	    } else {
	   	PTB( rdstrideSDS(sd_id,valstr->l2prods[i],stride,(VOIDP)&(valstr->data_val[l*totalpix])) );
		++l;
	    }
	}
	   
    }
    
    if (SDend(sd_id) == FAIL) {
       HY1C_out("-E- %s line %d: Could not close HDF file, %s .\n",__FILE__,__LINE__,valfile);
       return(HDF_FUNCTION_ERROR);
    }
    
    return(LIFE_IS_GOOD);
    
}    






/* ------------------------------------------------------         */
/* msval_npixs() - checks number of pixels contained in the       */
/*	    validation hdf file          	                  */
/* ------------------------------------------------------         */

int msval_npixs(char *valfile, int32_t subsmpl, int32_t *sensorID, int32_t *npixs, int32_t *ngranuls)
{

    int32 sd_id;
    int32 dim_sizes[H4_MAX_VAR_DIMS];
    intn  status;
    char  name[H4_MAX_NC_NAME];
    int32_t  totalpix=0, totalfiles=0;
    
    
    if (subsmpl <= 1) subsmpl = 1;    
    
    sd_id = SDstart(valfile, DFACC_RDONLY);
    if (sd_id == FAIL) {
       	HY1C_out("-E- %s line %d: Could not open HDF file, %s .\n",__FILE__,__LINE__,valfile);
       	return(HDF_FUNCTION_ERROR);
    }
    
    strcpy(name, "sensorID\0");
    read_glbl_attr(sd_id, name, (VOIDP)sensorID);    
    
    totalfiles = 0L;
    do {
	sprintf(name, "filename%d", totalfiles);
	    
  	if (SDfindattr(sd_id, name) == FAIL) break; else ++totalfiles;
	
    } while (1);

    strcpy(name, "fileID\0");
    if (getDims(sd_id, name, dim_sizes) != 0) {
       	HY1C_out("-E- %s line %d: Could not read HDF file dimensions, %s .\n",__FILE__,__LINE__,valfile);
        status = SDend(sd_id);
       	return(HDF_FUNCTION_ERROR);
    }
    if (dim_sizes[0] < 0){
    	HY1C_out("-E- %s line %d: The rank of the requested parameter (%s) is incorrect\n",__FILE__,__LINE__,name);
        status = SDend(sd_id);
    	return(-1);
    }
    totalpix = (int32_t)dim_sizes[0];
    
    if (subsmpl > 1) totalpix = (totalpix+subsmpl-1)/subsmpl;
       
    if (SDend(sd_id) == FAIL) {
       HY1C_out("-E- %s line %d: Could not close HDF file, %s .\n",__FILE__,__LINE__,valfile);
       return(HDF_FUNCTION_ERROR);
    }
    
    *npixs = totalpix;
    *ngranuls = totalfiles;
        
    return(LIFE_IS_GOOD);
    
}    





/* ------------------------------------------------------         */
/* msval_readblocks() - reads consecutive validation              */ 	          
/*          blocks of data of the size of 400,000 pixels       	  */		        
/*          calptr comprises the actual data for the 400,0000     */
/*          pixels, memory is allocated with the first use        */
/* ------------------------------------------------------         */

int msval_readblocks(char *valfile, int32 *sd_id, int32_t *spix, int32_t *totalpixs, msvalstr *valstr)
{

    int32 dim_sizes[H4_MAX_VAR_DIMS], sds_id;
    intn  status;
    char  name[H4_MAX_NC_NAME];
    int32_t  nfiles=0, i, l;
    int32 n_datasets, n_file_attr, rank, num_type, attributes;
    char  input_parms[16384], *ch;
    
    
    
    if (*spix >= *totalpixs) {
    	if (SDend(*sd_id) == FAIL) {
            HY1C_out("-E- %s line %d: Could not close HDF file, %s .\n",__FILE__,__LINE__,valfile);
            return(HDF_FUNCTION_ERROR);
    	}
    	free_valstr(*valstr, 1);
        valstr->npixs = 0L;
	return(LIFE_IS_GOOD);
    }
	
    
    if (*spix < 0L) {
    
        valstr->npixs = 0L;
	valstr->nfiles = 0L;
	
    	*sd_id = SDstart(valfile, DFACC_RDONLY);
    	if (*sd_id == FAIL) {
	    return(LIFE_IS_GOOD);
    	}
    
    	strcpy(name, "sensorID\0");
    	if (read_glbl_attr(*sd_id, name, (VOIDP) &(valstr->l2sensorID)) != LIFE_IS_GOOD) {
       	    HY1C_out("-E- %s line %d: Could not read HDF sensor attribute, %s .\n",__FILE__,__LINE__,valfile);
            status = SDend(*sd_id);
       	    return(HDF_FUNCTION_ERROR);
    	}
    
    	strcpy(name, "L3 validation sensorID\0");
    	if (read_glbl_attr(*sd_id, name, (VOIDP) &(valstr->l3sensorID)) != LIFE_IS_GOOD) {
       	    HY1C_out("-E- %s line %d: Could not read HDF L3 sensor attribute, %s .\n",__FILE__,__LINE__,valfile);
            status = SDend(*sd_id);
       	    return(HDF_FUNCTION_ERROR);
    	}
	
    	strcpy(name, "Input Parameters\0");
    	read_glbl_attr(*sd_id, name, (VOIDP) input_parms);
    	l = strlen(input_parms);
    	if ((valstr->input_parms = (char *)malloc((l+1)*sizeof(char))) == NULL) {
            HY1C_out("-E- %s line %d: Error allocating memory to MSl2validate input parameter text.\n",__FILE__,__LINE__);
            status = SDend(*sd_id);
       	    return(HDF_FUNCTION_ERROR);
     	}
    	strncpy(valstr->input_parms, input_parms, l);
    	valstr->input_parms[l] = '\x0';
    
    
    	nfiles = 0L;
    	do {
            sprintf(name, "filename%d", nfiles);
	    
  	    if (SDfindattr(*sd_id,name) == FAIL) break; else ++nfiles;
	
    	} while (1);

    
    	strcpy(name, "fileID\0");
    	if (getDims(*sd_id, name, dim_sizes) != 0) {
       	    HY1C_out("-E- %s line %d: Could not read HDF file dimensions, %s .\n",__FILE__,__LINE__,valfile);
            status = SDend(*sd_id);
       	    return(HDF_FUNCTION_ERROR);
    	}
    	if (dim_sizes[0] < 0){
    	    HY1C_out("-E- %s line %d: The rank of the requested parameter (%s) is incorrect\n",__FILE__,__LINE__,name);
            status = SDend(*sd_id);
    	    return(HDF_FUNCTION_ERROR);
     	}
    	*totalpixs = (int32_t)dim_sizes[0];
	
    	if (nfiles == 0L || *totalpixs == 0L) {
       	    HY1C_out("-E- %s line %d: There are no data in the file, %s .\n",__FILE__,__LINE__,name);
	    status = SDend(*sd_id);
      	    return(LIFE_IS_GOOD);
    	}
	

    	valstr->nl2prods = 1000;
    	if ((valstr->l2prods = (prname *)malloc(valstr->nl2prods*sizeof(prname))) == NULL) {
            HY1C_out("-E- %s line %d: Error allocating memory to l2 product names.\n",__FILE__,__LINE__);
            exit(FATAL_ERROR);
    	}
    	valstr->nl2prods = 0;
    	valstr->nl3prods = 1000;
    	if ((valstr->l3prods = (prname *)malloc(valstr->nl3prods*sizeof(prname))) == NULL) {
            HY1C_out("-E- %s line %d: Error allocating memory to L3 product names.\n",__FILE__,__LINE__);
            exit(FATAL_ERROR);
    	}
    	valstr->nl3prods = 0;
	
	
        SDfileinfo(*sd_id, &n_datasets, &n_file_attr);
    
    
    	for (i=0; i<n_datasets; i++) {
    
    	    sds_id = SDselect(*sd_id, i);
	    status = SDgetinfo(sds_id, name, &rank, dim_sizes, &num_type, &attributes);
	
	    if (strcmp(name, "fileID") == 0);
	    else 
	    if (strcmp(name, "year") == 0) ;
	    else 
	    if (strcmp(name, "day") == 0) ;
	    else 
	    if (strcmp(name, "msec") == 0) ;
	    else 
	    if (strcmp(name, "iscan") == 0) ;
	    else 
	    if (strcmp(name, "nscenes") == 0) ;
	    else 
	    if (strcmp(name, "nobs") == 0) ;
	    else 
	    if (strcmp(name, "lon") == 0) ;
	    else 
	    if (strcmp(name, "lat") == 0) ;
	    else 
            if ((ch = strstr(name, "_vic")) != NULL) {
	    
	    	strcpy(valstr->l3prods[valstr->nl3prods], name);
	    	valstr->nl3prods++;
	    }
	    else {
	    
	    	strcpy(valstr->l2prods[valstr->nl2prods], name);
	    	valstr->nl2prods++;
    	    } 
    	}
    
    	if ((valstr->l2prods = (prname *)realloc((void *)valstr->l2prods, valstr->nl2prods*sizeof(prname))) == NULL) {
            HY1C_out("-E- %s line %d: Error reallocating memory to l2 product names.\n",__FILE__,__LINE__);
            exit(FATAL_ERROR);
    	}
    	if ((valstr->l3prods = (prname *)realloc((void *)valstr->l3prods, valstr->nl3prods*sizeof(prname))) == NULL) {
            HY1C_out("-E- %s line %d: Error reallocating memory to L3 product names.\n",__FILE__,__LINE__);
            exit(FATAL_ERROR);
    	}
        valstr->l2Lambda = NULL;
	valstr->l3Lambda = NULL;
   
    
    	if (*totalpixs > 1000000) 
    	    l = alloc_valstr(nfiles, 1000000L, valstr);
	else
    	    l = alloc_valstr(nfiles, *totalpixs, valstr);
        

    	for (i=0; i<nfiles; i++) {
            sprintf(name, "filename%d", i);
	    
	    if (read_glbl_attr(*sd_id, name, (VOIDP) valstr->filenames[i]) != SUCCESS) {
	    	HY1C_out("-E- %s line %d: Error reading filename attributes (%s)\n",__FILE__,__LINE__,name);
            	status = SDend(*sd_id);
    		free_valstr(*valstr, 1);
        	valstr->npixs = 0L;
		valstr->nfiles = 0L;
    	    	return(HDF_FUNCTION_ERROR);
	    }
    
       	}
	
	*spix = 0L;
	
    } else {
    	
	if (*spix+valstr->npixs > *totalpixs) valstr->npixs = *totalpixs - *spix;
    }   
	    
    PTB( rdSDS(*sd_id,"fileID\0",(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->fileID) );
    PTB( rdSDS(*sd_id,"year\0",(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->year) );
    PTB( rdSDS(*sd_id,"day\0",(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->day) );
    PTB( rdSDS(*sd_id,"msec\0",(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->msec) );
    PTB( rdSDS(*sd_id,"lon\0",(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->lon) );
    PTB( rdSDS(*sd_id,"lat\0",(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->lat) );
    PTB( rdSDS(*sd_id,"iscan\0",(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->iscan) );
    PTB( rdSDS(*sd_id,"nscenes\0",(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->nscenes) );
    PTB( rdSDS(*sd_id,"nobs\0",(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->nobs) );
    for (i=0; i<valstr->nl3prods; i++)
	PTB( rdSDS(*sd_id,valstr->l3prods[i],(int32)*spix,0,valstr->npixs,0,(VOIDP)(valstr->data_vic+i*valstr->npixs)) );
	   
    l = 0;
    for (i=0; i<valstr->nl2prods; i++) {
    	if (strcmp(valstr->l2prods[i], "l2_flags\0") == 0) {
	    PTB( rdSDS(*sd_id,valstr->l2prods[i],(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->l2_flags) );
    	} else
    	if (strcmp(valstr->l2prods[i], "mside\0") == 0) {
	    PTB( rdSDS(*sd_id,valstr->l2prods[i],(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->mside) );
    	} else
    	if (strcmp(valstr->l2prods[i], "detnum\0") == 0) {
	    PTB( rdSDS(*sd_id,valstr->l2prods[i],(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->detnum) );
    	} else
    	if (strcmp(valstr->l2prods[i], "pixnum\0") == 0) {
	    PTB( rdSDS(*sd_id,valstr->l2prods[i],(int32)*spix,0,valstr->npixs,0,(VOIDP)valstr->pixnum) );
    	} else {
	    PTB( rdSDS(*sd_id,valstr->l2prods[i],(int32)*spix,0,valstr->npixs,0,(VOIDP)&(valstr->data_val[l*valstr->npixs])) );
	    ++l;
	}
    }

    *spix += valstr->npixs;
        
    return(LIFE_IS_GOOD);
    
}    





/* ------------------------------------------------------         */
/* msval_writeblocks() - writes consecutive validation            */ 	          
/*          blocks of data                              	  */		        
/*          calptr comprises the actual data for the 1,000,0000   */
/*          pixels, memory is allocated with the first use        */
/* ------------------------------------------------------         */

int msval_writeblocks(char *valfile, int32 sd_id, int32_t *spix, msvalstr valstr, int32_t nfiles)
{

    char  name[H4_MAX_NC_NAME];
    int32_t  i, j, l;

    idDS ds_id;
    ds_id.fid = sd_id;
    ds_id.fftype = FMT_L2HDF;
    
    if (nfiles < 0) nfiles = 0L;	
    
    if (*spix <= 0 || nfiles > 0) {
    
    	for (i=0; i<valstr.nfiles; i++) {
    	
    	   j = i + nfiles;
           sprintf(name, "filename%d", j);
	    
    	   PTB( SetChrGA(ds_id, name, (char *)valstr.filenames[i]) );
 		   
	}
	    
    }
	    
    PTB( sd_writedata(sd_id,"fileID\0",(VOIDP)valstr.fileID,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    PTB( sd_writedata(sd_id,"year\0",(VOIDP)valstr.year,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    PTB( sd_writedata(sd_id,"day\0",(VOIDP)valstr.day,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    PTB( sd_writedata(sd_id,"msec\0",(VOIDP)valstr.msec,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    PTB( sd_writedata(sd_id,"lon\0",(VOIDP)valstr.lon,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    PTB( sd_writedata(sd_id,"lat\0",(VOIDP)valstr.lat,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    PTB( sd_writedata(sd_id,"iscan\0",(VOIDP)valstr.iscan,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    PTB( sd_writedata(sd_id,"nscenes\0",(VOIDP)valstr.nscenes,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    PTB( sd_writedata(sd_id,"nobs\0",(VOIDP)valstr.nobs,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    for (i=0; i<valstr.nl3prods; i++)
	PTB( sd_writedata(sd_id,valstr.l3prods[i],(VOIDP)(valstr.data_vic+i*valstr.npixs),(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
	   
    l = 0;
    for (i=0; i<valstr.nl2prods; i++) {
    	if (strcmp(valstr.l2prods[i], "l2_flags\0") == 0) {
	    PTB( sd_writedata(sd_id,valstr.l2prods[i],(VOIDP)valstr.l2_flags,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    	} else
    	if (strcmp(valstr.l2prods[i], "mside\0") == 0) {
	    PTB( sd_writedata(sd_id,valstr.l2prods[i],(VOIDP)valstr.mside,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    	} else
    	if (strcmp(valstr.l2prods[i], "detnum\0") == 0) {
	    PTB( sd_writedata(sd_id,valstr.l2prods[i],(VOIDP)valstr.detnum,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    	} else
    	if (strcmp(valstr.l2prods[i], "pixnum\0") == 0) {
	    PTB( sd_writedata(sd_id,valstr.l2prods[i],(VOIDP)valstr.pixnum,(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
    	} else {
	    PTB( sd_writedata(sd_id,valstr.l2prods[i],(VOIDP)(valstr.data_val+l*valstr.npixs),(int32)*spix,0,0,(int32)valstr.npixs,1,1) );
	    ++l;
	}
    }

    *spix += valstr.npixs;
    
    return(LIFE_IS_GOOD);
    
}    



/* ------------------------------------------------------  */
/* rdstrideSDS() - reads complete SDS (scientific data set)*/
/*           for a given stride and returns the data       */
/*                                                         */
/* ------------------------------------------------------  */
int rdstrideSDS(int32 fileID, char *sdsname, int32 stride[2], VOIDP array_data)
{
   int32 sds_id, status, numtype;
   int32 sds_index, rank, dims[H4_MAX_VAR_DIMS], nattrs;
   int32 start[2], edges[2];
   char  tmp_sdsname[H4_MAX_NC_NAME];


   /* Get the SDS index */
   sds_index = SDnametoindex(fileID,sdsname);

   if (sds_index < 0) {
     HY1C_out("-E- %s: SDS \"%s\" not found.\n", "rdSDS",sdsname);
     status = SDend(fileID);
     return(HDF_FUNCTION_ERROR);
   }


   /* Select the SDS */
   if ((sds_id = SDselect(fileID, sds_index)) == FAIL) {
     HY1C_out("-E- %s line %d: Could not read parameter %s in HDF file.\n",__FILE__,__LINE__,sdsname);
     status = SDend(fileID);
     return(HDF_FUNCTION_ERROR);
   }

   /* Get the rank and number type of the array */
   if ((SDgetinfo(sds_id, tmp_sdsname, &rank, dims, &numtype, &nattrs)) == FAIL) {
     HY1C_out("-E- %s line %d: Could not get info about parameter %s in HDF file.\n",__FILE__,__LINE__,sdsname);
     status = SDend(fileID);
     return(HDF_FUNCTION_ERROR);
   }


   /* Define the location, pattern and size of the data to read */
   /* set 1st dimension */
   start[0] = 0;
   start[1] = 0;
   edges[0] = dims[0];
   /* if rank > 1, set 2nd dimension */
   if (rank > 1) edges[1] = dims[1];

   /* Based on number type, call the corresponding wrapper
   for the HDF SDreaddata function */ 
   if ((SDreaddata(sds_id, start, stride, edges, array_data)) == FAIL) {
     HY1C_out("-E- %s line %d: Could not read data for parameter %s in HDF file.\n",__FILE__,__LINE__,sdsname);
     status = SDend(fileID);
     return(HDF_FUNCTION_ERROR);
   }
    
   /* Terminate access to the array */
   if ((SDendaccess(sds_id)) == FAIL) {
     HY1C_out("-E- %s line %d: Could not end access for parameter %s in HDF file.\n",__FILE__,__LINE__,sdsname);
     status = SDend(fileID);
     return(HDF_FUNCTION_ERROR);
   }

   return(LIFE_IS_GOOD);
   
}


int read_glbl_attr(int32 sd_id, char *name, VOIDP ptr) 
{                                           

  int32 index;
  
  if ((index = SDfindattr(sd_id,name)) == FAIL) return(HDF_FUNCTION_ERROR);

  if (SDreadattr(sd_id,index,(VOIDP)ptr)){ 
    HY1C_out("-E- %s line %d: Could not get global attribute, %s.\n", __FILE__,__LINE__,(name));
    return(HDF_FUNCTION_ERROR);
  }

  return(LIFE_IS_GOOD);
                                                         
}   








int32_t alloc_valstr(int32_t nfiles, int32_t npixs, msvalstr *valstr)
{
    
    int32_t  len, i;
    unsigned char  *p;
    
    
    len = nfiles*sizeof(stname) + 6*npixs*sizeof(int16) + npixs*sizeof(int32) + 2*npixs*sizeof(float32);
    
    for (i=0; i<valstr->nl3prods; i++) len += npixs*sizeof(float32);
    
    for (i=0; i<valstr->nl2prods; i++) {
    
    	if (strcmp(valstr->l2prods[i], "l2_flags") == 0) len += npixs*sizeof(int32);
	else
    	if (strcmp(valstr->l2prods[i], "mside") == 0) len += npixs*sizeof(uint8);
        else
    	if (strcmp(valstr->l2prods[i], "detnum") == 0) len += npixs*sizeof(uint8);
    	else
    	if (strcmp(valstr->l2prods[i], "pixnum") == 0) len += npixs*sizeof(int16);
    	else
	len += npixs*sizeof(float32);
    }
    
        
    if ((p = (unsigned char *) malloc(len)) == NULL) {
	HY1C_out("%s -Error: Cannot allocate memory to validation data\n",__FILE__);
   	exit(FATAL_ERROR);
    }
    valstr->nfiles = nfiles;
    valstr->npixs = npixs;
    valstr->data = p;
    valstr->filenames = (stname *)  p; p += nfiles*sizeof(stname);
    valstr->fileID = 	(int16 	*)  p; p += npixs*sizeof(int16);
    valstr->year = 	(int16 	*)  p; p += npixs*sizeof(int16);
    valstr->day = 	(int16 	*)  p; p += npixs*sizeof(int16);
    valstr->msec = 	(int32 	*)  p; p += npixs*sizeof(int32);
    valstr->lon = 	(float32 *) p; p += npixs*sizeof(float32);
    valstr->lat = 	(float32 *) p; p += npixs*sizeof(float32);
    valstr->iscan = 	(int16 	 *) p; p += npixs*sizeof(int16);
    valstr->nscenes = 	(int16 	 *) p; p += npixs*sizeof(int16);
    valstr->nobs = 	(int16 	 *) p; p += npixs*sizeof(int16);
    valstr->data_vic =  (float32 *) p; p += npixs*valstr->nl3prods*sizeof(float32);
    for (i=0; i<valstr->nl2prods; i++) {
    	if (strcmp(valstr->l2prods[i], "l2_flags") == 0) {
    	    valstr->l2_flags = 	(int32 	*) p; p += npixs*sizeof(int32);
    	} else
    	if (strcmp(valstr->l2prods[i], "mside") == 0) {
	    valstr->mside = 	(uint8 	*) p; p += npixs*sizeof(uint8);
        } else
    	if (strcmp(valstr->l2prods[i], "detnum") == 0) {
	    valstr->detnum = 	(uint8 	*) p; p += npixs*sizeof(uint8);
        } else
    	if (strcmp(valstr->l2prods[i], "pixnum") == 0) {
	    valstr->pixnum = 	(int16 	*) p; p += npixs*sizeof(int16);
        }
    }
    valstr->data_val =  (float32 *) p;
    
    return(len);
    
}
   







void free_valstr(msvalstr valstr, int all)
{
     if (valstr.data != NULL) free(valstr.data);
     valstr.data = NULL;
     
     if (all) {
        if (valstr.l2Lambda != NULL) free(valstr.l2Lambda); valstr.l2Lambda = NULL;
	if (valstr.l2prods != NULL) free(valstr.l2prods); valstr.l2prods = NULL;
	if (valstr.l3Lambda != NULL) free(valstr.l3Lambda); valstr.l3Lambda = NULL;
	if (valstr.l3prods != NULL) free(valstr.l3prods); valstr.l3prods = NULL;
	if (valstr.input_parms != NULL) free(valstr.input_parms); valstr.input_parms = NULL;
     }
     
}


